package main

import (
	"bytes"
	"encoding/binary"
	"flag"
	"fmt"
	"log"
	"math/rand"
	"net"
	"os"
	"sync"
	"sync/atomic"
	"time"

	"github.com/rcrowley/go-metrics"
)

/*
case 0x99: //TEST
		echo.Write(encodeTime(body[0:8]))

./t -addr ***:11101 -count 500 -step 20 > a.log


完成初始化 500 累计:5000   本次总连接时长 11.526450874s, each:23.052902ms
online:5000, offline:0
metrics: 21:29:51.037093 timer ops
metrics: 21:29:51.037115   count:         1927000
metrics: 21:29:51.037158   min:                15.17ms
metrics: 21:29:51.037166   max:               281.77ms
metrics: 21:29:51.037172   mean:               25.22ms
metrics: 21:29:51.037180   stddev:             17.78ms
metrics: 21:29:51.037185   median:             22.62ms
metrics: 21:29:51.037189   75%:                26.35ms
metrics: 21:29:51.037194   95%:                38.85ms
metrics: 21:29:51.037199   99%:                52.67ms
metrics: 21:29:51.037203   99.9%:             281.76ms
metrics: 21:29:51.037208   1-min rate:       8205.34
metrics: 21:29:51.037213   5-min rate:       4318.33
metrics: 21:29:51.037217   15-min rate:      1857.10
metrics: 21:29:51.037222   mean rate:        4941.00


使用了CPU 不到20%  内存不到10%

*/

var addr = flag.String("addr", "127.0.0.1:10320", "default address")
var count = flag.Int("count", 1, "并发数")
var start = flag.Int("start", 1, "起始数")
var step = flag.Int("step", 1, "步长")
var startMetric = flag.String("sm", time.Now().Format("2006-01-02T15:04:05 -0700"), "start time point of all clients")
var opsRate = metrics.NewRegisteredTimer("ops", nil)

var online, offline int32

func main() {

	flag.Parse()

	fmt.Println("send:", *addr)
	id := 111111111111111
	go func() {
		metrics.LogScaled(metrics.DefaultRegistry, 30*time.Second, time.Millisecond, log.New(os.Stdout, "metrics: ", log.Lmicroseconds))
	}()
	go func() {
		t := time.NewTicker(30 * time.Second)
		for {
			<-t.C
			fmt.Printf("online:%d, offline:%d  \n", online, offline)
		}
	}()
	for i := 0; i < *step; i++ {

		s := +(*step * *count) * i

		Worker(id, s, *count)
		// fmt.Println(id, s, *count)
		time.Sleep(30 * time.Second)
	}

	select {}
}

func Worker(id, start, count int) {
	gs := make([]*GPSConn, 0, count)
	tt := time.Now()
	for i := start; i < start+count; i++ {
		// 连接服务器
		conn, err := net.Dial("tcp", *addr)
		if err != nil {
			fmt.Println("Connect to TCP server failed ,err:", err)
			return
		}
		g := GPSConn{}
		g.conn = conn
		g.imei = fmt.Sprintf("%d", id+i)
		gs = append(gs, &g)
		atomic.AddInt32(&online, 1)
	}

	fmt.Printf("完成初始化 %d 累计:%d   本次总连接时长 %v, each:%v\n", len(gs), online, time.Now().Sub(tt), time.Now().Sub(tt)/time.Duration(len(gs)))

	for i := 0; i < len(gs); i++ {
		conn := gs[i]
		conn.run()
	}
}

type GPSConn struct {
	conn  net.Conn
	imei  string
	count int
}

func (g *GPSConn) run() {
	go g.write()
}

func (g *GPSConn) write() {

	defer func() {
		if err := recover(); err != nil {
			fmt.Printf("recover: %s,err:%v\n", g.imei, err)
		}
		fmt.Println(g.imei + " done")
		atomic.AddInt32(&offline, 1)
	}()
	t := time.NewTicker(time.Second + time.Duration(rand.Intn(1300)+1))
	<-t.C

	now := time.Now()
	_, err := g.conn.Write(g.login())
	if err != nil {
		fmt.Println("Write failed,err:", err)
	}
	g.read(now, "login")
	// time.Sleep(30 * time.Second)

	for {
		select {
		case <-t.C:
			now = time.Now()
			_, err := g.conn.Write(g.test())
			if err != nil {
				fmt.Println("Write heartbeat failed,err:", err)
			}
			g.read(now, "test")

			// _, err = g.conn.Write(g.sync())
			// if err != nil {
			// 	fmt.Println("Write heartbeat failed,err:", err)
			// }
			// g.read(now, "sync")
		}
	}
}

func (g *GPSConn) read(t time.Time, label string) error {
	var buf [10240]byte
	n, err := g.conn.Read(buf[:])
	if err != nil {
		fmt.Println("read", err)
		panic("read err")
	}
	_ = n

	opsRate.Update(time.Now().Sub(t))

	g.count++
	if label == "login" || true {
		// fmt.Printf("imei:%s read %s, len:%d ts:%v\n", g.imei, label, n, time.Now().Sub(t))
	}
	if label == "test" {

		n := int64(binary.BigEndian.Uint64(buf[0:n]))

		last := time.Unix(n/1e9, n%1e9)

		opsRate.Update(time.Now().Sub(last))
		// fmt.Println("read:", n, "time:", time.Now().Sub(last))
		// resp.inc((time.Now().UnixNano() - last.UnixNano()) / int64(time.Millisecond))
	}

	return err
}

func (g *GPSConn) login() []byte {

	var buf bytes.Buffer

	buf.Write(Append(toHex(g.imei), 5))                              //sn
	buf.Write(timeToBytes())                                         //时间
	buf.Write(Append([]byte{0x00}, 1))                               //重启原因
	buf.Write(Append(toHex(g.imei), 8))                              //imsi
	buf.Write(Append(toHex(g.imei), 8))                              //imei
	buf.Write(Append([]byte{0, 0}, 2))                               //终端功能
	buf.Write(Append([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 8)) //厂家编号
	buf.WriteString("NS_TEST_WA")                                    //版本号

	var cache bytes.Buffer
	cache.Write(uint16ToBytes((uint16)(buf.Len() + 12))) //长度
	cache.WriteByte(0x00)                                //版本号
	cache.WriteByte(0x01)                                //命令码
	cache.WriteByte(0x01)                                //流水号
	cache.Write([]byte{0x00, 0x00, 0x00})                //预留字段
	cache.Write(buf.Bytes())                             //装载数据

	var write bytes.Buffer
	write.Write([]byte{0xAA, 0xAA})
	write.Write(cache.Bytes())
	write.Write(uint16ToBytes(CRC16ITU(cache.Bytes())))

	// fmt.Println(time.Now(), "login ", g.imei)
	return write.Bytes()
}

func (g *GPSConn) heartbeat() []byte {
	var buf bytes.Buffer

	buf.Write(Append(toHex(g.imei), 5)) //sn
	buf.Write([]byte{0x00, 0x00})       //gsm
	buf.Write([]byte{0x00, 0x00})       //车辆状态
	buf.Write([]byte{0x00, 0x00})       //电瓶电压
	buf.Write([]byte{0x00})             //soc
	buf.Write([]byte{0x00, 0x00})       //gsm

	var cache bytes.Buffer
	cache.Write(uint16ToBytes((uint16)(buf.Len() + 12))) //长度
	cache.WriteByte(0x00)                                //版本号
	cache.WriteByte(0x05)                                //命令码
	cache.WriteByte(0x04)                                //流水号
	cache.Write([]byte{0x00, 0x00, 0x00})                //预留字段
	cache.Write(buf.Bytes())                             //装载数据

	var write bytes.Buffer
	write.Write([]byte{0xAA, 0xAA})
	write.Write(cache.Bytes())
	write.Write(uint16ToBytes(CRC16ITU(cache.Bytes())))

	// fmt.Println(time.Now(), "heartbeat ", g.imei)
	return write.Bytes()
}

func (g *GPSConn) sync() []byte {
	var buf bytes.Buffer

	buf.Write(Append(toHex(g.imei), 5)) //sn
	buf.Write(timeToBytes())            //时间
	buf.WriteString("AA=BB")            //版本号

	var cache bytes.Buffer
	cache.Write(uint16ToBytes((uint16)(buf.Len() + 12))) //长度
	cache.WriteByte(0x00)                                //版本号
	cache.WriteByte(0x09)                                //命令码
	cache.WriteByte(0x04)                                //流水号
	cache.Write([]byte{0x00, 0x00, 0x00})                //预留字段
	cache.Write(buf.Bytes())                             //装载数据

	var write bytes.Buffer
	write.Write([]byte{0xAA, 0xAA})
	write.Write(cache.Bytes())
	write.Write(uint16ToBytes(CRC16ITU(cache.Bytes())))

	// fmt.Println(time.Now(), "heartbeat ", g.imei)
	return write.Bytes()
}

func (g *GPSConn) test() []byte {
	var buf bytes.Buffer

	buf.Write(timeNano()) //时间

	var cache bytes.Buffer
	cache.Write(uint16ToBytes((uint16)(buf.Len() + 12))) //长度
	cache.WriteByte(0x00)                                //版本号
	cache.WriteByte(0x99)                                //命令码
	cache.WriteByte(0x04)                                //流水号
	cache.Write([]byte{0x00, 0x00, 0x00})                //预留字段
	cache.Write(buf.Bytes())                             //装载数据

	var write bytes.Buffer
	write.Write([]byte{0xAA, 0xAA})
	write.Write(cache.Bytes())
	write.Write(uint16ToBytes(CRC16ITU(cache.Bytes())))

	// fmt.Println(time.Now(), "heartbeat ", g.imei)
	return write.Bytes()
}

func chanelclose() {
	done := make(chan bool)

	for i := 0; i < 10; i++ {
		go func(num int) {
			fmt.Println(num, "start")
			select {
			case <-done:
				fmt.Println(num, "done")
			}
			fmt.Println(num, "start")
		}(i)
	}

	time.Sleep(10 * time.Second)

	close(done)
	fmt.Println("done close")

	time.Sleep(10 * time.Second)
	return
}

func def() {
	defer func() {
		fmt.Println("default all")
	}()

	i := 10
	for i > 0 {
		defer func(num int) {
			fmt.Println("default ", num)
		}(i)
		i--
	}

	fmt.Println("function")
}

func syncMap() {
	s := sync.Map{}
	s.Store("1", 1)
	s.Store("2", 2)
	s.Store("3", 3)

	s.Range(func(key, value interface{}) bool {
		fmt.Println(key, value)
		return true
	})

	s.Load("")
	fmt.Println("--------")
	s.Range(func(key, value interface{}) bool {
		fmt.Println(key, value)
		return true
	})

	fmt.Println(s)

	return
}
